﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class PlayerVisionScript : MonoBehaviour {

	float detectRange = 20f;
	float detectAngle = 75f;
	float memoryTime = 1.0f;
	Dictionary<int,GameObject> visibleEnemies = new Dictionary<int,GameObject>();
	Dictionary<int,GameObject> memoryEnemies = new Dictionary<int,GameObject>();

	// Use this for initialization
	void Start () {
		
	}

	public void addVisibleEnemy(GameObject obj){
		makeInstantlyVisible (obj);
		visibleEnemies.Add(obj.GetComponent<EnemyMainAIScript>().id, obj);
	}
	
	// Update is called once per frame
	void Update () {
		checkForEnemy ();
		checkForNonVisibleEnemy ();
	}
	
	void checkForEnemy(){
		Collider[] collide = Physics.OverlapSphere (new Vector3 (transform.position.x, transform.position.y, transform.position.z), detectRange, 1 << LayerMask.NameToLayer ("EnemyNPC"));
		if (collide.Length > 0) {
			foreach(Collider col in collide){
				if(checkVisionAngle(col.attachedRigidbody.transform.position)){
					if(checkObstacles(col.attachedRigidbody.transform.position)){
						if(!visibleEnemies.ContainsKey(col.attachedRigidbody.GetComponent<EnemyMainAIScript>().id)){
							if(memoryEnemies.ContainsKey(col.attachedRigidbody.GetComponent<EnemyMainAIScript>().id)){
								memoryEnemies.Remove(col.attachedRigidbody.GetComponent<EnemyMainAIScript>().id);
							}
							StartCoroutine(makeVisible(col.attachedRigidbody.gameObject));
							visibleEnemies.Add(col.attachedRigidbody.GetComponent<EnemyMainAIScript>().id, col.attachedRigidbody.gameObject);
						}
					}
				}
			}
		}
	}

	void checkForNonVisibleEnemy(){
		ICollection keys = visibleEnemies.Keys;
		foreach (int i in keys) {
			GameObject obj = visibleEnemies[i];
			if(!checkVisionAngle(obj.transform.position) || !checkObstacles(obj.transform.position)){
				visibleEnemies.Remove(obj.GetComponent<EnemyMainAIScript>().id);
				memoryEnemies.Add(obj.GetComponent<EnemyMainAIScript>().id, obj);
				StartCoroutine(makeInvisible(obj));
			}
		}
	}

	IEnumerator makeVisible(GameObject obj){
		Component[] comp = obj.GetComponentsInChildren<MeshRenderer> ();
		Color temp;
		int count = 0;
		while (true) {
			foreach (MeshRenderer c in comp) {
				temp = c.material.color;
				temp.a += 1.0f/10.0f;
				c.material.color = temp;
				if(c.material.color.a < 1){
					count++;
				}
			}
			temp = obj.renderer.material.color;
			temp.a += 1.0f/10.0f;
			obj.renderer.material.color = temp;
			if(obj.renderer.material.color.a < 1){
				count++;
			}
			yield return new WaitForSeconds(memoryTime/100.0f);
			if(count == 0){
				break;
			}
			count = 0;
		}
	}

	IEnumerator makeInvisible(GameObject obj){
		Component[] comp = obj.GetComponentsInChildren<MeshRenderer> ();
		Color temp;
		int count = 0;
		while (true) {
			foreach (MeshRenderer c in comp) {
				temp = c.material.color;
				temp.a -= 1.0f/100.0f;
				c.material.color = temp;
				if(c.material.color.a > 0){
					count++;
				}
			}
			temp = obj.renderer.material.color;
			temp.a -= 1.0f/100.0f;
			obj.renderer.material.color = temp;
			if(obj.renderer.material.color.a > 0){
				count++;
			}
			if(count == 0){
				memoryEnemies.Remove(obj.GetComponent<EnemyMainAIScript>().id);
				break;
			}
			if(!memoryEnemies.ContainsKey(obj.GetComponent<EnemyMainAIScript>().id)){
				break;
			}
			count = 0;
			yield return new WaitForSeconds(memoryTime/100.0f);
		}
	}

	void makeInstantlyVisible(GameObject obj){
		Component[] comp = obj.GetComponentsInChildren<MeshRenderer> ();
		Color temp;
		foreach (MeshRenderer c in comp) {
			temp = c.material.color;
			temp.a = 1.0f;
			c.material.color = temp;
		}
		temp = obj.renderer.material.color;
		temp.a = 1.0f;
		obj.renderer.material.color = temp;
	}

	bool checkObstacles(Vector3 position){
		RaycastHit hit;
		Vector3 direction = new Vector3 (position.x - transform.position.x, position.y - transform.position.y, position.z - transform.position.z);
		Ray ray = new Ray (transform.position, direction);
		if (Physics.Raycast (ray, out hit, Vector3.Distance (transform.position, position))) {
			if (hit.collider.tag == "Enemy") {
				return true;
			} else {
				return false;
			}
		}
		//Debug.DrawRay (transform.position, direction, Color.blue, 1);
		return false;
	}
	
	bool checkVisionAngle(Vector3 position){
		Vector3 targetDir = position - transform.position;
		float angle = Vector3.Angle(targetDir, transform.forward);
		if (angle <= detectAngle) {
			return true;
		} else {
			return false;
		}
	}
}
